#include "pylon.h"

pylon::pylon()
{
    PylonInitialize();
    GDALAllRegister();
    gpio = new Gpio;
    V30D = new lux;
    connect(gpio,SIGNAL(shotSignal()), this, SLOT(shotSlot()));
    connect(this,SIGNAL(startSignal()), gpio,SLOT(timerStartSlot()));
}

pylon::~pylon()
{
    PylonTerminate();
    delete gpio;
    delete V30D;
}

void pylon::run()
{
    try
    {
        // Create an instant camera object with the camera device found first.
        CBaslerUniversalInstantCamera camera( CTlFactory::GetInstance().CreateFirstDevice() );
        // Print the model name of the camera.
        camera.Open();
        cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;

        // The parameter MaxNumBuffer can be used to control the count of buffers
        // allocated for grabbing. The default value of this parameter is 10.
        camera.MaxNumBuffer = 10;
        exposure = V30D->getExpo();
        if(exposure > 8000) {
            exposure = 8000;
        }

        camera.PixelFormat.SetValue( PixelFormat_Mono12 );
        camera.ExposureTime.SetValue( exposure );

        // Start the grabbing of c_countOfImagesToGrab images.
        // The camera device is parameterized with a default configuration which
        // sets up free-running continuous acquisition.
        camera.StartGrabbing(c_countOfImagesToGrab);

        // This smart pointer will receive the grab result data.
        CGrabResultPtr ptrGrabResult;

        GDALDataset *poDstDS;
        GDALDriver  *poDriver;
        GDALRasterBand *poBand;
        CPLErr err;
        char **papszOptions = NULL;
        QString time;
        QDateTime current_date_time = QDateTime::currentDateTime();
        time = current_date_time.toString("yyyy_MM_dd_hh_mm_ss_zzz");
        time.append(".tif");
        string ch = time.toStdString();
        const char* name = ch.c_str();

        poDriver = GetGDALDriverManager()->GetDriverByName("Gtiff");
        poDstDS = poDriver->Create( name, 1920, 4 * c_countOfImagesToGrab, 300, GDT_UInt16, papszOptions);

        // Camera.StopGrabbing() is called automatically by the RetrieveResult() method
        // when c_countOfImagesToGrab images have been retrieved.
        timer.start();
        emit startSignal();
        while (camera.IsGrabbing())
        {
            if(gpio->pylonstopflag == 1)
                break;
            // Wait for an image and then retrieve it. A timeout of 5000 ms is used.
            camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException );

            // Image grabbed successfully?
            if (ptrGrabResult->GrabSucceeded())
            {
                // Access the image data.
                uint16_t *pImageBuffer = (uint16_t *) ptrGrabResult->GetBuffer();

                //Copy image data in array
                for(int band = 0; band < 300; band++) {
                    for(int num = 0; num < 7680; num++) {
                        WaveBand[band][num] = pImageBuffer[pix];
                        pix++;
                    }
                }
                qDebug() << "data copy time is " << timer.elapsed() << "milliseconds";
                //Write array data in raster file
                for(int i = 0; i < 300; i++) {
                    poBand = poDstDS->GetRasterBand(i+1);
                    err = poBand->RasterIO( GF_Write, 0, row, 1920, 4,
                                      WaveBand[i], 1920, 4, GDT_UInt16, 0, 0 );
                }
                qDebug() << "data write time is " << timer.elapsed() << "milliseconds";
                poDstDS->FlushCache();
                pix = 0;
                row += 4;
            }
            else
            {
                cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << endl;
            }
        }
        qDebug() << "Total time is " << timer.elapsed() << "milliseconds";
        row = 0;
        GDALClose( (GDALDatasetH) poDstDS );
        stopflag = 0;
    }
    catch (const GenericException& e)
    {
        // Error handling.
        cerr << "An exception occurred." << endl
            << e.GetDescription() << endl;
    }
    cout << "end" << endl << endl;
}

const char* pylon::getName()
{
    QString time;
    QDateTime current_date_time = QDateTime::currentDateTime();
    time = current_date_time.toString("yyyy_MM_dd_hh_mm_ss_zzz");
    time.append(".tif");
    string ch = time.toStdString();
    const char* name = ch.c_str();

    return name;
}

void pylon::shotSlot()
{
    this->start();
}


